package pl.elka.pszt.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

import javax.swing.JOptionPane;

/**
 * Klasa generyzujaca bazy wiedzy
 * 
 * @author Robert Strulak
 * 
 */
public class KnowledgeGenerator {
	public static final String PATH_TO_RESOURCES = "/src/pl/elka/pszt/resources/";

	public static final String FILE_NAME = "knowledge_";
	public static final String FILE_FORMAT = ".txt";
	private SimpleDateFormat sdf;
	private String sdfString = new String();
	private String sdfOldString = new String();
	private int sdfCounter = 0;
	private File file;

	public KnowledgeGenerator() {
		sdf = new SimpleDateFormat("MM_dd-HH_mm_ss");
	}

	/**
	 * Generuje baza wiedzy w nastepujacym formacie: <br>
	 * A1() -> A2 -> ... -> An -> A(n+1)() <br>
	 * B1() -> B2 -> ... -> Bn -> A(n+1)() <br>
	 * . <br>
	 * . <br>
	 * . <br>
	 * N1() -> N2 -> ... -> Nn -> A(n+1)() <br>
	 * 
	 * @param streamLength
	 *            Dlugosc poszczegolnych strumieni (ilosc implikacji w kazdym ze
	 *            strumieni)
	 * @param streamCount
	 *            Ilosc strumieni
	 * @param factRatio
	 *            stosunek faktow do ilosci strumieni, np 1 - wszystkie
	 *            strumienie moja lisc potwierdzony faktem
	 * @return Nazwa pliku zawierajacego wygenerowana wiedze
	 */
	public String generateKnowledgeWithoutConjuction(int streamLength,
			int streamsCount, double factRatio) {
		file = new File(getFileName());
		try {
			PrintWriter pw = new PrintWriter(file);
			for (int j = 0; j < streamsCount; j++) {
				generateKlausule(pw, genereteAAAfunction(j), streamLength);
			}
			for (int j = 0; j < streamsCount; j++) {
				generateLastKlausule(pw, genereteAAAfunction(j),
						Character.toString('A'), streamLength);
			}
			pw.println();

			int ratio = (int) (factRatio * streamsCount);
			if (ratio == 0) {
				ratio = 1;
			}

			Set<Integer> randomNumberSet = new HashSet<>();
			while (randomNumberSet.size() < ratio) {
				randomNumberSet.add(getRandomNumber(streamsCount));
			}
			Iterator<Integer> iter = randomNumberSet.iterator();
			while (iter.hasNext()) {
				generateFact(pw, genereteAAAfunction((int) iter.next()));
			}
			pw.flush();
			pw.close();

			return file.getName();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * Metodo analogiczna do generateKnowledgeWithoutConjuction, z ta roznica,
	 * ze poszczegolne strumienie w punkcie okreslonym jako cutPosition
	 * rozdzielaja sie i lacza (jezeli to mozliwe) ze strumieniem znajdujacy sie
	 * bezposrednio nad i po.
	 * 
	 * @param streamLength
	 *            Dlugosc poszczegolnych strumieni (ilosc implikacji w kazdym ze
	 *            strumieni)
	 * @param streamCount
	 *            Ilosc strumieni
	 * @param cutPosition
	 *            Miejsce rozdzielenia strumienia - stosunek do dlugosci
	 *            poszczegolnych strumieni
	 * @return Nazwa pliku zawierajacego wygenerowana wiedze
	 */
	public String generateKnowledgeWithConjuction(int streamLength,
			int streamsCount, double cutPosition) {
		file = new File(getFileName());
		if (cutPosition >= 1) {
			JOptionPane.showMessageDialog(null,
					"Parametr cutPosition musi nalezec do przedzialu (0 - 1)!",
					"Information", JOptionPane.INFORMATION_MESSAGE);
			return null;
		}
		try {
			PrintWriter pw = new PrintWriter(file);
			for (int j = 0; j < streamsCount; j++) {
				generateKlausule(pw, genereteAAAfunction(j), streamLength);
			}
			for (int j = 0; j < streamsCount; j++) {
				generateLastKlausule(pw, genereteAAAfunction(j),
						genereteAAAfunction(j), streamLength);
			}
			pw.println();

			int cutIndex = (int) (streamLength * cutPosition);
			if (cutIndex == 0) {
				cutIndex = 1;
			}

			for (int k = 0; k < streamsCount; k++) {
				if (k < streamsCount - 1) {
					generateKlausule(pw, genereteAAAfunction(k),
							genereteAAAfunction(k), cutIndex);
				}
			}
			pw.println();
			for (int j = 0; j < streamsCount; j++) {
				generateFact(pw, genereteAAAfunction(j));
			}

			pw.flush();
			pw.close();
			return file.getName();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}

	}

	private String genereteAAAfunction(int j) {
		int charNum, repeatNum;
		StringBuilder finalString = new StringBuilder();

		if (j == 0) {
			return Character.toString((char) (65));
		}

		charNum = j % 26;

		repeatNum = (j - charNum) / 26;
		for (int i = 0; i <= repeatNum; i++) {
			finalString.append((char) (65 + charNum));
		}
		return finalString.toString();

	}

	private void generateKlausule(PrintWriter pw, String character1,
			String character2, int cutPosition) {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("");
		stringBuilder.append(character1);
		stringBuilder.append(cutPosition);
		stringBuilder.append("(x");
		stringBuilder.append(cutPosition);
		stringBuilder.append(",const) => ");
		stringBuilder.append(character2);
		stringBuilder.append(cutPosition + 1);
		stringBuilder.append("(x");
		stringBuilder.append(cutPosition + 1);
		stringBuilder.append(",const)");
		pw.println(stringBuilder.toString());

	}

	private int getRandomNumber(int n) {
		Random random = new Random();
		return random.nextInt(n);
	}

	private void generateLastKlausule(PrintWriter pw, String character1,
			String character2, int streamLength) {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("");
		stringBuilder.append(character1);
		stringBuilder.append(streamLength);
		stringBuilder.append("(x");
		stringBuilder.append(streamLength);
		stringBuilder.append(",const) => ");
		stringBuilder.append(character2);
		stringBuilder.append(streamLength + 1);
		stringBuilder.append("(x");
		stringBuilder.append(streamLength);
		stringBuilder.append(",const)");
		pw.println(stringBuilder.toString());

	}

	private String getFileName() {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append(System.getProperty("user.dir"));
		stringBuilder.append(PATH_TO_RESOURCES);
		stringBuilder.append(FILE_NAME);
		stringBuilder.append(sdf.format(new Date()));
		stringBuilder.append(FILE_FORMAT);
		return stringBuilder.toString();
		// StringBuilder stringBuilder = new StringBuilder();
		// // stringBuilder.append(System.getProperty("user.dir"));
		//
		// stringBuilder.append(PATH_TO_RESOURCES);
		// stringBuilder.append(FILE_NAME);
		//
		// sdfString = sdf.format(new Date()).toString();
		//
		// if (sdfOldString.equals(sdfString)) {
		// sdfCounter++;
		// stringBuilder.append(sdfString);
		// stringBuilder.append("_(" + sdfCounter + ")");
		// } else {
		// sdfCounter = 0;
		// stringBuilder.append(sdfString);
		// sdfOldString = sdfString;
		// }
		// stringBuilder.append(FILE_FORMAT);
		// return stringBuilder.toString();
	}

	private void generateKlausule(PrintWriter pw, String character,
			int streamLength) {
		for (int i = 0; i < streamLength; i++) {
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.append("");
			stringBuilder.append(character);
			stringBuilder.append(i);
			stringBuilder.append("(x");
			stringBuilder.append(i);
			stringBuilder.append(",const) => ");
			stringBuilder.append(character);
			stringBuilder.append((i + 1));
			stringBuilder.append("(x");
			stringBuilder.append(i);
			stringBuilder.append(",const)");
			pw.println(stringBuilder.toString());
		}
		pw.println();
	}

	private void generateFact(PrintWriter pw, String character) {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("");
		stringBuilder.append(character);
		stringBuilder.append("0(Const1,Const2)");
		pw.println(stringBuilder.toString());
	}

	public static void main(String[] args) {
		KnowledgeGenerator knowledgeGenerator = new KnowledgeGenerator();

		knowledgeGenerator.generateKnowledgeWithoutConjuction(5, 100, 0.3);
		knowledgeGenerator.generateKnowledgeWithoutConjuction(100, 5, 0.9);
		knowledgeGenerator.generateKnowledgeWithoutConjuction(100, 5, 0.5);
		knowledgeGenerator.generateKnowledgeWithoutConjuction(100, 100, 0.3);

		knowledgeGenerator.generateKnowledgeWithConjuction(100, 5, 0.5);
		knowledgeGenerator.generateKnowledgeWithConjuction(10, 50, 0.1);
		knowledgeGenerator.generateKnowledgeWithConjuction(10, 17, 0.99);

		// knowledgeGenerator.generateKnowledgeWithConjuction(999, 999, 0.3);

	}
}
